#ifndef MAPPED_OBJECT_H
#define MAPPED_OBJECT_H

#include <stdexcept>
#include <limits>
#include <stdint.h>
// basic mapped objects.

struct MemoryMappedObject {
	template <typename This>
	void* get_void_pointer_after() {
		return reinterpret_cast<char*>(this)+sizeof (This);
	}
	template <typename This, typename Ret>
	Ret* get_pointer_after() {
		return reinterpret_cast<Ret*>(get_void_pointer_after<This>());
	}

	// same thing, except it's const.
	template <typename This>
	const void* get_void_pointer_after() const {
		return reinterpret_cast<const char*>(this)+sizeof (This);
	}
	template <typename This, typename Ret>
	const Ret* get_pointer_after() const {
		return reinterpret_cast<const Ret*>(
				get_void_pointer_after<This>());
	}
};

struct MemoryMappedPointer {
	typedef uint32_t value_type;
	value_type address;
	bool operator < (const MemoryMappedPointer& o) const {
		return address < o.address;
	}
	bool operator == (const MemoryMappedPointer& o) const {
		return address == o.address;
	}
};

template <typename T>
struct PointerTo : MemoryMappedObject {
	MemoryMappedPointer pointer;

	bool operator <(const PointerTo<T>& o) const {
		return pointer < o.pointer;
	}
	bool operator ==(const PointerTo<T>& o) const {
		return pointer == o.pointer;
	}
};

struct MemoryMappedUInt : MemoryMappedObject {
	uint32_t value;
};

struct MemoryMappedFloat : MemoryMappedObject {
	float value;
};

struct MemoryMappedDouble : MemoryMappedObject {
	double value;
};


// currently useless, might factor things in that later.
struct MemoryMappedTableHeader : MemoryMappedObject {
};

struct MemoryMappedPascalString : MemoryMappedObject {
	uint8_t size;
	size_t get_total_size() const {
		return sizeof (MemoryMappedPascalString) + size;
	}
	static size_t get_needed_size(const std::string& str) {
		return sizeof (MemoryMappedPascalString) + str.size();
	}
	std::string get_string() const {
		const char* raw_str;
		raw_str = get_pointer_after<MemoryMappedPascalString, char>();
		// if you plan about printing this string there ... FUCKING DONT
		// remember that this string is NOT nul terminated.
		return std::string(raw_str, size);
	}
	void set_from(const std::string& str) {
		if (str.size() > std::numeric_limits<uint8_t>::max())
			throw std::logic_error("string is too large");
		size = str.size();
		memcpy(get_pointer_after<MemoryMappedPascalString, char>(),
			str.c_str(), size);
	}
};


template <typename T> class MemoryMappedTableContent;


template <typename T> 
struct MappedTable {

	// Content of a table.
	struct MemoryMappedContent : MemoryMappedObject {
		T* getElement(ptrdiff_t i=0) {
			void* this_star = this;
			return i + reinterpret_cast<T*>(this_star);
		}
	};
	typedef MemoryMappedContent content_type;

	size_t size;
	MemoryMappedContent& table;
	MappedTable(size_t _size, MemoryMappedContent& _table) :
		size(_size), table(_table) {}

	T* getElement(size_t i = 0) {
		if (i >= size)
			throw std::logic_error("invalid table element access");

		return table.getElement(i);
		
	}


	typedef T value_type;
	typedef T* iterator;
	typedef const T* const_iterator;
	T* begin() { return table.getElement(0); }
	T* end() { return table.getElement(size); }


	size_t get_total_size() const {
		return size * sizeof(T);
	}
	template <typename T2> T2* get_pointer_after() {
		void* ret = table.getElement(0) + size;
		return reinterpret_cast<T2*>(ret);
	}
};





#endif
